#include "../../../Include/DataType/String/WizDataTypeUTF8.hpp"
#include "../../../Include/DataType/String/WizDataTypeUTF16.hpp"
#include "../../../Include/DataType/String/WizDataTypeUTF32.hpp"

namespace Wiz
{
	namespace UTF32
    {
        ////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////
        WIZ_INLINE ::Wiz::Size32::Type LenFromOtherUTF
            ( 
            ::Wiz::UTF16::Char::InPtr	Src,
            ::Wiz::Size32::InOut        SrcBytes	/// In:Remained  Out:Used
            )
        {
            return ::Wiz::UTF::UTF32Length(Src, SrcBytes);
        }

        WIZ_INLINE ::Wiz::Size32::Type LenFromOtherUTF
            ( 
            ::Wiz::UTF32::Char::InPtr	Src,
            ::Wiz::Size32::InOut        SrcBytes	/// In:Remained  Out:Used
            )
        {
            if (SrcBytes < 1)
            {
                return 0;
            }
            SrcBytes = 1;
            return 1;
        }

        WIZ_INLINE ::Wiz::Size32::Type LenToOtherUTF
            (
            ::Wiz::UTF16::Char::Type    WIZ_UNUSED(FLAGS),
            ::Wiz::UTF32::Char::InPtr	Src,
            ::Wiz::Size32::InOut        SrcBytes	/// In:Remained  Out:Used
            )
        {
            return ::Wiz::UTF::UTF16Length(Src, SrcBytes);
        }

        WIZ_INLINE ::Wiz::Size32::Type LenToOtherUTF
            (
            ::Wiz::UTF32::Char::Type    WIZ_UNUSED(FLAGS),
            ::Wiz::UTF32::Char::InPtr	Src,
            ::Wiz::Size32::InOut        SrcBytes	/// In:Remained  Out:Used
            )
        {
            if (SrcBytes < 1)
            {
                return 0;
            }
            SrcBytes = 1;
            return 1;
        }
        ////////////////////////////////////////////////////////////////////////

        WIZ_INLINE ::Wiz::Size32::Type LenFromWChar
            (
            ::Wiz::WChar::InPtr			Src,
            ::Wiz::Size32::InOut        SrcBytes	/// In:Remained  Out:Used
            )
        {
            typedef ::Wiz::TypeTraits::If<sizeof(::Wiz::WChar::Type) == sizeof(::Wiz::UTF16::Char::Type), ::Wiz::UTF16::Char::InPtr, ::Wiz::UTF32::Char::InPtr>::tType SrcType;
            return ::Wiz::UTF32::LenFromOtherUTF(::Wiz::Cast::Static<SrcType>(Src), SrcBytes);
        }

        WIZ_INLINE ::Wiz::Size32::Type LenToWChar
            (
            ::Wiz::UTF32::Char::InPtr	Src,
            ::Wiz::Size32::InOut        SrcBytes	/// In:Remained  Out:Used
            )
        {
            typedef ::Wiz::TypeTraits::If<sizeof(::Wiz::WChar::Type) == sizeof(::Wiz::UTF16::Char::Type), ::Wiz::UTF16::Char::Type, ::Wiz::UTF32::Char::Type>::tType SrcType;
            return ::Wiz::UTF32::LenToOtherUTF(::Wiz::Cast::Static<SrcType>(0), Src, SrcBytes);
        }

        ////////////////////////////////////////////////////////////////////////
        WIZ_INLINE ::Wiz::UTF::eResult FromOtherUTF
            ( 
            ::Wiz::UTF32::Char::OutPtr   Dest,
            ::Wiz::Size32::InOut        DestBytes,  /// In:Remained  Out:Used
            ::Wiz::UTF16::Char::InPtr	Src,
            ::Wiz::Size32::InOut        SrcBytes	/// In:Remained  Out:Used
            )
        {
            return ::Wiz::UTF::ConvertUTF16toUTF32(Dest, DestBytes, Src, SrcBytes);
        }

        WIZ_INLINE ::Wiz::UTF::eResult FromOtherUTF
            ( 
            ::Wiz::UTF32::Char::OutPtr   Dest,
            ::Wiz::Size32::InOut        DestBytes,  /// In:Remained  Out:Used
            ::Wiz::UTF32::Char::InPtr	Src,
            ::Wiz::Size32::InOut        SrcBytes	/// In:Remained  Out:Used
            )
        {
            Dest[0] = Src[0];
            DestBytes = SrcBytes = 1;
            return ::Wiz::UTF::eSuccess;
        }

        WIZ_INLINE ::Wiz::UTF::eResult ToOtherUTF
            (
            ::Wiz::UTF16::Char::OutPtr	Dest,
            ::Wiz::Size32::InOut        DestBytes,  /// In:Remained  Out:Used
            ::Wiz::UTF32::Char::InPtr	Src,
            ::Wiz::Size32::InOut        SrcBytes	/// In:Remained  Out:Used
            )
        {
            return ::Wiz::UTF::ConvertUTF32toUTF16(Dest, DestBytes, Src, SrcBytes);
        }

        WIZ_INLINE ::Wiz::UTF::eResult ToOtherUTF
            (
            ::Wiz::UTF32::Char::OutPtr	Dest,
            ::Wiz::Size32::InOut        DestBytes,  /// In:Remained  Out:Used
            ::Wiz::UTF32::Char::InPtr	Src,
            ::Wiz::Size32::InOut        SrcBytes	/// In:Remained  Out:Used
            )
        {
            Dest[0] = Src[0];
            DestBytes = SrcBytes = 1;
            return ::Wiz::UTF::eSuccess;
        }
        ////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////

        ////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////
        WIZ_INLINE ::Wiz::UTF::eResult FromWChar
            (
            ::Wiz::UTF32::Char::OutPtr   Dest,
            ::Wiz::Size32::InOut        DestBytes,  /// In:Remained  Out:Used
            ::Wiz::WChar::InPtr			Src,
            ::Wiz::Size32::InOut        SrcBytes	/// In:Remained  Out:Used
            )
        {
            typedef ::Wiz::TypeTraits::If<sizeof(::Wiz::WChar::Type) == sizeof(::Wiz::UTF16::Char::Type), ::Wiz::UTF16::Char::InPtr, ::Wiz::UTF32::Char::InPtr>::tType SrcType;
            return ::Wiz::UTF32::FromOtherUTF(Dest, DestBytes, ::Wiz::Cast::Static<SrcType>(Src), SrcBytes);
        }

        WIZ_INLINE ::Wiz::UTF::eResult ToWChar
            (
            ::Wiz::WChar::OutPtr        Dest,
            ::Wiz::Size32::InOut        DestBytes,  /// In:Remained  Out:Used
            ::Wiz::UTF32::Char::InPtr	Src,
            ::Wiz::Size32::InOut        SrcBytes	/// In:Remained  Out:Used
            )
        {
            typedef ::Wiz::TypeTraits::If<sizeof(::Wiz::WChar::Type) == sizeof(::Wiz::UTF16::Char::Type), ::Wiz::UTF16::Char::OutPtr, ::Wiz::UTF32::Char::OutPtr>::tType DestType;
            return ::Wiz::UTF32::ToOtherUTF(::Wiz::Cast::Static<DestType>(Dest), DestBytes, Src, SrcBytes);
        }
        ////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////
		namespace String
		{
			::Wiz::Void::Type Type::From(::Wiz::WString::In WStr)
			{
				this->From(WStr.GetCStr(), WStr.Size());
			}

			::Wiz::Void::Type Type::From(::Wiz::UTF8::String::In U8Str)
			{
                this->From(U8Str.GetCStr(), U8Str.Size());
			}

			::Wiz::Void::Type Type::From(::Wiz::UTF16::String::In U16Str)
            {
                this->From(U16Str.GetCStr(), U16Str.Size());
			}

			::Wiz::Void::Type Type::From(::Wiz::String::In Str, ::Wiz::Char::InPtr CP)
            {
                ::Wiz::WString::Type WStr;
                if (::Wiz::MultiBytesStrToWCharStr(WStr, Str, CP))
                {
                    this->From(WStr.GetCStr(), WStr.Size());
                }
			}

			::Wiz::Void::Type Type::From(::Wiz::WChar::InPtr WStrPtr, ::Wiz::Size::In Len)
            {
                ::Wiz::Size32::Type RealSrcLen = Len;
                if (RealSrcLen == 0)
                {
                    RealSrcLen = wcslen(WStrPtr) + 1;
                }

                ::Wiz::Size32::Type i, j, RealDestLen = 0, SrcLen, DestLen;
                for (i = 0; i < RealSrcLen; i += SrcLen)
                {
                    SrcLen = RealSrcLen - i;
                    DestLen = ::Wiz::UTF32::LenFromWChar(&WStrPtr[i], SrcLen);
                    if (DestLen == 0)
                    {
                        return;
                    }
                    RealDestLen += DestLen;
                }
                this->Resize(RealDestLen);

                for (i = 0, j = 0; i < RealSrcLen; i += SrcLen, j += DestLen)
                {
                    SrcLen  = RealSrcLen - i;
                    DestLen = RealDestLen - j;
                    if (::Wiz::UTF32::FromWChar(&(this->GetBuffer()[j]), DestLen, &WStrPtr[i], SrcLen) != ::Wiz::UTF::eSuccess)
                    {
                        this->Resize(j);
                        return;
                    }
                }
			}

			::Wiz::Void::Type Type::From(::Wiz::UTF8::Char::InPtr U8Ptr, ::Wiz::Size::In Len)
            {
                ::Wiz::Size32::Type RealSrcLen = Len;

                ::Wiz::Size32::Type i, j, RealDestLen = 0, SrcLen, DestLen;
                for (i = 0; i < RealSrcLen; i += SrcLen)
                {
                    SrcLen = RealSrcLen - i;
                    DestLen = ::Wiz::UTF::UTF32Length(&U8Ptr[i], SrcLen);
                    if (DestLen == 0)
                    {
                        return;
                    }
                    RealDestLen += DestLen;
                }
                this->Resize(RealDestLen);

                for (i = 0, j = 0; i < RealSrcLen; i += SrcLen, j += DestLen)
                {
                    SrcLen  = RealSrcLen - i;
                    DestLen = RealDestLen - j;
                    if (::Wiz::UTF::ConvertUTF8toUTF32(&(this->GetBuffer()[j]), DestLen, &U8Ptr[i], SrcLen) != ::Wiz::UTF::eSuccess)
                    {
                        this->Resize(j);
                        return;
                    }
                }
			}

			::Wiz::Void::Type Type::From(::Wiz::UTF16::Char::InPtr U16Ptr, ::Wiz::Size::In Len)
            {
                ::Wiz::Size32::Type RealSrcLen = Len;

                ::Wiz::Size32::Type i, j, RealDestLen = 0, SrcLen, DestLen;
                for (i = 0; i < RealSrcLen; i += SrcLen)
                {
                    SrcLen = RealSrcLen - i;
                    DestLen = ::Wiz::UTF::UTF32Length(&U16Ptr[i], SrcLen);
                    if (DestLen == 0)
                    {
                        return;
                    }
                    RealDestLen += DestLen;
                }
                this->Resize(RealDestLen);

                for (i = 0, j = 0; i < RealSrcLen; i += SrcLen, j += DestLen)
                {
                    SrcLen  = RealSrcLen - i;
                    DestLen = RealDestLen - j;
                    if (::Wiz::UTF::ConvertUTF16toUTF32(&(this->GetBuffer()[j]), DestLen, &U16Ptr[i], SrcLen) != ::Wiz::UTF::eSuccess)
                    {
                        this->Resize(j);
                        return;
                    }
                }
			}

			::Wiz::Void::Type Type::From(::Wiz::Char::InPtr CharPtr, ::Wiz::Size::In Len, ::Wiz::Char::InPtr CP)
            {
                ::Wiz::Size32::Type RealSrcLen = Len;
                if (RealSrcLen == 0)
                {
                    RealSrcLen = strlen(CharPtr);
                }

                ::Wiz::String::Type Str;
                ::Wiz::String::MakeCStr(Str, CharPtr, RealSrcLen);

                this->From(CP, Str);
			}

            ////////////////////////////////////////////////////////////////////
            ::Wiz::WChar::ConstPtr Type::To(::Wiz::WString::Out WStr) const
            {
                ::Wiz::Size32::Type StrLen = this->Size();

                ::Wiz::Size32::Type i, j, RealLen = 0, SrcLen, DestLen;
                for (i = 0; i < StrLen; i += SrcLen)
                {
                    SrcLen = StrLen - i;
                    DestLen = ::Wiz::UTF32::LenToWChar(this->GetCStr() + i, SrcLen);
                    if (DestLen == 0)
                    {
                        return WIZ_NULLPTR;
                    }
                    RealLen += DestLen;
                }
                WStr.Resize(RealLen);

                for (i = 0, j = 0; i < StrLen; i += SrcLen, j += DestLen)
                {
                    SrcLen  = StrLen - i;
                    DestLen = RealLen - j;
                    if (::Wiz::UTF32::ToWChar(WStr.GetBuffer() + j, DestLen, GetCStr() + i, SrcLen) != ::Wiz::UTF::eSuccess)
                    {
                        WStr.Resize(j);
                        return WStr.GetCStr();
                    }
                }

                return WStr.GetCStr();
            }
            ::Wiz::Char::ConstPtr  Type::To(::Wiz::String::Out Str, ::Wiz::Char::InPtr CP) const
            {
                ::Wiz::WString::Type WStr;
                this->To(WStr);

                if (::Wiz::WCharStrToMultiBytesStr(Str, WStr, CP) == ::Wiz::Bool::False)
                {
                    return WIZ_NULLPTR;
                }

                return Str.GetCStr();
            }
            ////////////////////////////////////////////////////////////////////
		} /// end of namespace String
	} /// end of namespace UTF32
} /// end of namespace Wiz


